#ifndef CSERVER_SESSION_NODE_H
#define CSERVER_SESSION_NODE_H
#include <boost/asio/io_service.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/udp.hpp>
#include <cserver/range.h>
#include <cserver/protocol.h>

namespace csrv{
	class Context;
	union HeadData{
		HeadProtocolFire head_fire;
		HeadProtocol head;
		char buffer[sizeof(HeadProtocol)];
	};

	using ResponseSenderType = std::function<void(const std::vector<char>&)>;
	class NodeProtocol : public std::enable_shared_from_this<NodeProtocol> {
		public:
			Context& context;
			NodeProtocol(Context& ctx);

			HeadType checkHead(const HeadData&);

			void process(const std::string& ip_addr_port, const HeadProtocol&, const char* buf, size_t size, ResponseSenderType sender);
			void process_fire(const std::string& ip_addr_port, const HeadProtocolFire&, const char* buf, size_t size, ResponseSenderType sender );
		protected:
			bool process_soak(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_hydrant(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_well_lid(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_sprinkler(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_firedoor(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_firepool(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_firebox(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_environment(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, ResponseSenderType sender);
			bool process_voice(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, ResponseSenderType sender);
			bool process_fire_pump(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_water_quality(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, ResponseSenderType sender);

			bool process_electric(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, ResponseSenderType sender);
			bool process_device_init_response(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_threshold_response(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_date_update(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, ResponseSenderType sender);
			bool process_xhs_electric(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, ResponseSenderType sender);
			bool process_fire_pump__and_fan_info(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, uint16_t cmd);
			bool process_waterater_data(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid);
			bool process_sponge_data(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, ResponseSenderType sender);
			bool process_sponge_upconfig(const std::string& ip_addr_port, const char* buf, size_t size, std::string& euid, ResponseSenderType sender);

			boost::asio::ip::udp::socket socket_forward;
	};

	class NodeTcp : public NodeProtocol
	{
		public:
			explicit NodeTcp(Context& ctx, std::shared_ptr<boost::asio::ip::tcp::socket> s);
			void start(boost::asio::yield_context yield);
		private:
			void run_(boost::asio::yield_context yield);
			std::shared_ptr<boost::asio::ip::tcp::socket> socket;
	};
	using NodeTcpPtr = std::shared_ptr<NodeTcp>;

	class NodeUdp : public NodeProtocol
	{
		public:
			explicit NodeUdp(Context& ctx);
			void start();
		private:
			void run_(boost::asio::yield_context yield);
			void run_xhs_(boost::asio::yield_context yield);
	};
	using NodeUdpPtr = std::shared_ptr<NodeUdp>;



}

#endif //end CSERVER_SESSION_NODE_H



